var camera, scene, renderer;
var cameraControls;
var clock = new THREE.Clock();
var canvasWidth = 846;
var canvasHeight = 494;
var canvasRatio = canvasWidth / canvasHeight;
var raycaster;
var projector;
var objects = [];
var startGameFlag = 0;

THREE.Vector3.prototype.unproject = function () {
    var matrix;
    return function ( camera ) {
    if ( matrix === undefined ) 
        matrix = new THREE.Matrix4();
    matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
    return this.applyProjection( matrix );
    };
}();
function onDocumentMouseDown( event ) {
    if (startGameFlag === 1) {
        //Find mouse click position in the canvas space
        var canvasPosition = renderer.domElement.getBoundingClientRect();
        var mouseX = event.clientX - canvasPosition.left;
        var mouseY = event.clientY - canvasPosition.top;

        //The axis of reference became the center of the canvas
        var mouseVector = new THREE.Vector3(
                2 * ( mouseX / canvasWidth ) - 1,
                1 - 2 * ( mouseY / canvasHeight ));

        //create a raycaster
        var raycaster = projector.pickingRay( mouseVector.clone(), camera );
        //get all ojbects 
        var intersects = raycaster.intersectObjects( objects, true );
        
        //Check the objects that interpted the mouse click event
        if ( intersects.length > 0 ) {
            var target = new THREE.Mesh(
            new THREE.PlaneGeometry(100, 100),
            new THREE.MeshPhongMaterial({color: 0xFFFFFF,
                polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0
            }));
            
            target.position.set(intersects[0].object.position.x, intersects[0].object.position.y+20, intersects[0].object.position.z);
            
            scene.add(target);
            intersects[0].object.position.set(
                    intersects[0].object.position.x + 25, 
                    intersects[0].object.position.y,
                    intersects[0].object.position.z + 25
            );
        }
    }
}

function startGame() {
    if(startGameFlag === 0) {
        var tween = new TWEEN.Tween({ x: -700, y: 500 } )
                .to( { x: -370, y: 550 }, 2000 )
                .repeat(0)
                .onUpdate( function () {
                    camera.position.set(this.x, this.y, 0);
                } )
                .start();
        startGameFlag = 1;
    }
}

function finishGame() {
    if(startGameFlag === 1) {
        var tween = new TWEEN.Tween({ x: -370, y: 550 } )
                .to( { x: -700, y: 500 }, 2000 )
                .repeat(0)
                .onUpdate( function () {
                    camera.position.set(this.x, this.y, 0);
                } )
                .start();
        startGameFlag = 0;
    }
}
            
function createTable(){
    
    var legMaterial = new THREE.MeshPhongMaterial({
        color: 0xCCCCCC,
        map: THREE.ImageUtils.loadTexture('textures/diffuse/wood.jpg'),
        bumpMap: THREE.ImageUtils.loadTexture('textures/bump/wood.jpg'),
        normalMap: THREE.ImageUtils.loadTexture('textures/normal/wood.png')
    });
    
   
    var legGeometry = new THREE.BeveledBlockGeometry( 30, 300, 30, 8 );
    var boardGeometry = new THREE.BeveledBlockGeometry( 400, 20, 400, 4 );
  
    {
    var leg1 = new THREE.Mesh(legGeometry, legMaterial );
    leg1.position.set(150, 150, 150);
    
    var leg2 = new THREE.Mesh(legGeometry, legMaterial );
    leg2.position.set(150, 150, -150);
    
    var leg3 = new THREE.Mesh(legGeometry, legMaterial );
    leg3.position.set(-150, 150, 150);
    
    var leg4 = new THREE.Mesh(legGeometry, legMaterial );
    leg4.position.set(-150, 150, -150);
    
    var horTable = new THREE.Object3D();
    horTable.add(new THREE.Mesh(boardGeometry, legMaterial ));
    horTable.position.set(0, 300, 0);
    }
    
    var table = new THREE.Object3D();
    table.add(horTable);
    table.add(leg1);
    table.add(leg2);
    table.add(leg3);
    table.add(leg4);
    return table;
}

function createCheckerBoard() {
    var boardGeometry = new THREE.BeveledBlockGeometry( 200, 5, 200, 0 );
    var boardMaterial = new THREE.MeshPhongMaterial({
        color: 0xEEEEDD,
        map: THREE.ImageUtils.loadTexture('textures/diffuse/checker.jpg'),
        normalMap: THREE.ImageUtils.loadTexture('textures/normal/checker.jpg')
    });

    var woodGeometry = new THREE.BeveledBlockGeometry(205, 15, 5, 2);
    var woodMaterial = new THREE.MeshPhongMaterial({
        color: 0x5C412D,
        transparent: true,
        opacity: 0.9
    });
    
    var bar1 = new THREE.Mesh(woodGeometry, woodMaterial);
    var bar2 = new THREE.Mesh(woodGeometry, woodMaterial);
    var bar3 = new THREE.Mesh(woodGeometry, woodMaterial);
    var bar4 = new THREE.Mesh(woodGeometry, woodMaterial);
    var gameBoard = new THREE.Mesh(boardGeometry, boardMaterial);
    
    var board = new THREE.Object3D();
    board.add(gameBoard);
    
    bar1.position.set(0, 5, 100);
    board.add(bar1);
    
    bar2.position.set(0, 5, -100);
    board.add(bar2);
    
    bar3.rotation.y = Math.PI/2;
    bar3.position.set(-100, 5, 0);
    board.add(bar3);
    
    bar4.position.set(100, 5, 0);
    bar4.rotation.y = Math.PI/2;
    board.add(bar4);

    return board;
}

function createPiece(op, color){   
    var material;
    var piece = new THREE.Object3D();
    if (color === "yellow")
        material = new THREE.MeshPhongMaterial({color: 0xFFFF00});
    else
        material = new THREE.MeshPhongMaterial({color: 0x008400});
    var geometry = new THREE.CylinderGeometry( 8, 8, 5, 64 );
    
    var torusGeo = new THREE.TorusGeometry( 7, 1, 8, 64 );
    var torusGeo2 = new THREE.TorusGeometry( 3, 1, 8, 64 );
    
    var torus = new THREE.Mesh(torusGeo, material);
    torus.position.y = 2.5;
    torus.rotation.x = Math.PI/2;

    var torus2 = new THREE.Mesh(torusGeo2, material);
    torus2.position.y = 2.5;
    torus2.rotation.x = Math.PI/2;

    var normalPiece = new THREE.Mesh(geometry, material);
    
    if (op===1) { //if piece is normal piece
        //piece.add(torus);
        //piece.add(torus2);
        piece.add(normalPiece);
        return piece;
    }
    else { //piece is special
        piece.add(torus);
        //piece.add(torus2);
        piece.add(normalPiece);
        return piece;
    }
}

function createGameScene(){
    var table = createTable();
    var checkerBoard = createCheckerBoard();
    checkerBoard.position.y = 310;
    var gameScene = new THREE.Object3D();
    var piece;
    
    for (var i=0; i<12; i++) {
        piece = createPiece(1, "yellow");
        piece.position.y = 315;
        if(Math.floor(i/4) === 2) {
            piece.position.x = -39;
            piece.position.z = -87+(i%4)*50;
        }
        else if(Math.floor(i/4) === 1) {
            piece.position.x = -63;
            piece.position.z = -63+(i%4)*50;
        }
        else {
            piece.position.x = -86;
            piece.position.z = -87+(i%4)*50;
        }
        
        objects.push( piece );
        gameScene.add(piece);
    }
    
    for (var i=0; i<12; i++) {
        piece = createPiece(1, "green");
        piece.position.y = 315;
        if(Math.floor(i/4) === 2) {
            piece.position.x = -39 + 125;
            piece.position.z = -87+(i%4)*50 + 25;
        }
        else if(Math.floor(i/4) === 1) {
            piece.position.x = -63 + 125;
            piece.position.z = -63+(i%4)*50 - 25;
        }
        else {
            piece.position.x = -86 + 125;
            piece.position.z = -87+(i%4)*50 + 25;
        }
        objects.push( piece );
        gameScene.add(piece);
    }
    
    
    gameScene.add(table);
    gameScene.add(checkerBoard);
    
    gameScene.traverse( function ( object ) {
                    if (object instanceof THREE.Mesh) {
                        object.castShadow = true;
                        object.receiveShadow = true;
                    }
                });
                
    return gameScene;
}

function fillScene() {
    scene = new THREE.Scene();
    //scene.fog = new THREE.Fog(0x808080, 2000, 4000);

    // LIGHTS
    var ambientLight = new THREE.AmbientLight(0x222222);
    scene.add(ambientLight);
    
    var spotLight = new THREE.SpotLight(0xFFFFFF, 1.5);
    spotLight.position.set(-400, 1200, -100);
    //spotLight.angle = 20 * Math.PI / 180;
    spotLight.exponent = 1;
    spotLight.castShadow = true;
    spotLight.target.position.set(0, 200, 0);
    scene.add(spotLight);
    
    var texture = THREE.ImageUtils.loadTexture('textures/diffuse/floor.jpg');
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set( 32, 32 );
    texture.anisotropy = renderer.getMaxAnisotropy();
    var texture2 =  THREE.ImageUtils.loadTexture('textures/diffuse/wall.jpg');
    texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping;
    texture2.repeat.set( 2, 2 );
    texture2.anisotropy = renderer.getMaxAnisotropy();
    
    var solidGround = new THREE.Mesh(
            new THREE.PlaneGeometry(3000, 3000),
            new THREE.MeshPhongMaterial({
                polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0,
                map: texture
                
            }));
           
    solidGround.rotation.x = -Math.PI / 2;
    solidGround.receiveShadow = true;
    scene.add(solidGround);
    scene.add(createGameScene()); 
    
    var backWall = new THREE.Mesh(
            new THREE.PlaneGeometry(3000, 700),
            new THREE.MeshPhongMaterial({
                color: 0xFFFFFF,
                polygonOffset: true, polygonOffsetFactor: 1.0, polygonOffsetUnits: 4.0,
                map: texture2
                
            }));
    
    backWall.rotation.y = -Math.PI /2;
    backWall.position.x = 1500;
    backWall.position.y = 350;
    scene.add(backWall);
    
    //Camera Control
    cameraControls = new THREE.OrbitAndPanControls(camera, renderer.domElement);
    cameraControls.target.set(0, 200, 0);
    var delta = clock.getDelta();
    cameraControls.update(delta);
}

function init() {
    // RENDERER
    renderer = new THREE.WebGLRenderer({antialias: false});
    renderer.gammaInput = true;
    renderer.gammaOutput = true;
    renderer.setSize(canvasWidth, canvasHeight);
    renderer.setClearColorHex(0xAAAAAA, 1.0);
    renderer.shadowMapEnabled = true;
    // CAMERA
    camera = new THREE.PerspectiveCamera(40, canvasRatio, 1, 10000);
    camera.position.set(-700, 500, 0);
    
    projector = new THREE.Projector();
    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}

function addToDOM() {
    var container = document.getElementById('container');
    var canvas = container.getElementsByTagName('canvas');
    if (canvas.length > 0) {
        container.removeChild(canvas[0]);
    }
    container.appendChild(renderer.domElement);
}

function animate(time) {
    window.requestAnimationFrame(animate);
    TWEEN.update( time );
    render();
    
}

function render() {
    renderer.render(scene, camera);
}

function createScene() {
    try {
        init();
        fillScene();
        addToDOM();
        animate();
    } catch (e) {
        var errorReport = "Your program encountered an unrecoverable error, can not draw on canvas. Error was:<br/><br/>";
        $('#container').append(errorReport + e);
    }
}